﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

using SVNTreeViewer.Views;

namespace SVNTreeViewer.VisualTreeBuilder
{
    /// <summary>
    /// Path between two points.
    /// </summary>
    public class PathPainter
    {
        private readonly Brush strokeColor = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF89C3E8"));

        private Dictionary<int, long> dc = new Dictionary<int, long>();

        /// <summary>
        /// Paths the specified p1.
        /// </summary>
        /// <param name="p1">The p1.</param>
        /// <param name="p2">The p2.</param>
        /// <returns>Path between two points.</returns>
        public Path Path(Point p1, Point p2)
        {
            bool drawingDown = p1.Y < p2.Y;
            Geometry data = drawingDown
                                ? Geometry.Parse(
                                    "M " + FormatPointString(new Point(p1.X + 35, p1.Y + 4)) + " v "
                                    + FormatPointString(p2.Y - p1.Y - 64) + " c 0,20 0,20 20,20 h "
                                    + FormatPointString(p2.X - p1.X - 50) + " c 30,0 30,0 30,20")
                                : Geometry.Parse(
                                    "M " + FormatPointString(new Point(p1.X + 35, p1.Y - 20)) + " c 0,-20 0,-20 30,-20 h "
                                    + FormatPointString(p2.X - p1.X - 50) + " c 20,0 20,0 20,-20 v "
                                    + FormatPointString(p2.Y - p1.Y + 100));

            Path path = new Path
            {
                StrokeLineJoin = PenLineJoin.Round,
                Stroke = this.strokeColor,
                StrokeThickness = 2,
                Data = data
            };

            return path;
        }

        /// <summary>
        /// Partials the path.
        /// </summary>
        /// <param name="p1">The p1.</param>
        /// <param name="p2">The p2.</param>
        /// <returns>Path between two points.</returns>
        public Path PartialPath(Point p1, Point p2)
        {
            bool drawingDown = p1.Y < p2.Y;

            Geometry data = drawingDown
                                ? Geometry.Parse(
                                    "M " + FormatPointString(new Point(p1.X + 35, p1.Y + 4)) + " v "
                                    + FormatPointString(p2.Y - p1.Y - 64) + " c 0,20 0,20 20,20 h ")
                                : Geometry.Parse(
                                    "M " + FormatPointString(new Point(p1.X + 35, p1.Y - 20)) + " c 0,-20 0,-20 30,-20 h "
                                    + FormatPointString(p2.X - p1.X - 50));

            Path partialPath = new Path
            {
                StrokeLineJoin = PenLineJoin.Round,
                Stroke = this.strokeColor,
                StrokeThickness = 2,
                ////StrokeDashArray = DoubleCollection.Parse("2,2"),
                Data = data
            };

            //// TODO: command do wszystkich kresek idacych do tego samego wezla, aby sie podswietlily :)

            return partialPath;
        }

        /// <summary>
        /// Gets the path.
        /// </summary>
        /// <param name="blockFrom">The block from.</param>
        /// <param name="blockTo">The block to.</param>
        /// <returns>Path between two points.</returns>
        public UIElement GetPath(RevisionBlock blockFrom, RevisionBlock blockTo)
        {
            //// path is being drawn down or up.
            if (blockFrom.Location.Y < blockTo.Location.Y)
            {
                //// we dont want the corner of the blocks but rather it's middle to start/end our line.
                Point p1 = new Point(blockFrom.Location.X + 35, blockFrom.Location.Y);
                Point p2 = new Point(blockTo.Location.X + 35, blockTo.Location.Y - 20);

                //// avoid collisions
                int y = Convert.ToInt32(p2.Y - 20);

                Path p = new Path();
                p.Stroke = this.strokeColor;
                p.StrokeThickness = 2;
                p.Data = Geometry.Parse(
                        "M " + FormatPointString(new Point(p1.X, p1.Y + 4)) + " v "
                        + FormatPointString(p2.Y - p1.Y - 64) + " c 0,20 0,20 20,20 h "
                        + FormatPointString(p2.X - p1.X - 50) + " c 30,0 30,0 30,20");

                return p;
            }

            return new Polyline();
        }

        private static string FormatPointString(Point p1)
        {
            return Convert.ToInt32(p1.X) + "," + Convert.ToInt32(p1.Y);
        }

        private static string FormatPointString(double p)
        {
            return Convert.ToInt32(p).ToString(CultureInfo.InvariantCulture);
        }
    }
}